package mgoDB

import (
	"fmt"
	"strconv"
	"sync"
	"time"

	"go.mongodb.org/mongo-driver/mongo"
)

var (
	contentMap = sync.Map{}     //数据库
	contentMu sync.Mutex        //数据库锁定防止并发访问

	repositoryMap = sync.Map{}  //仓储
	repositoryMu = sync.Mutex{} //仓储锁定防止并发访问
)

//MgoContent 数据库上下文
type MgoContent struct {
	database     *mongo.Database
	timeout      time.Duration
}

//DataBaseMapping 添加映射
// @client 连接对象
// @dataName 数据库名
func DataBaseMapping(config map[string]string) (*MgoContent,error) {
	ipport := config["ipport"]
	dbname := config["dbname"]
	key := fmt.Sprint(ipport,"@#",dbname)
	value, ok := contentMap.Load(key)
	if ok {
		return value.(*MgoContent), nil
	}
	contentMu.Lock()
	defer contentMu.Unlock()

	value, ok = contentMap.Load(key)
	if ok {
		return value.(*MgoContent), nil
	}
	timeout := time.Second * 30
	if timeoutStr, ok := config["timeout"]; ok {
		atoi, err := strconv.Atoi(timeoutStr)
		if err == nil {
			timeout = time.Second * time.Duration(atoi)
		}
	}
	client, err := GetMgoClient(config)
	if err != nil {
		return nil, err
	}
	database := client.Database(dbname)
	content := &MgoContent{
		database: database,
		timeout:  timeout,
	}
	contentMap.Store(key, content)
	return content, nil
}

// GetMgoRepository 获取集合仓储
// collectionName  结构体
// indexFn        索引创建
func (m *MgoContent) GetMgoRepository(collectionName string,indexFn func(RepositoryIndexes)) IMgoRepository {
	var key = fmt.Sprint(m.database.Name(), "@#@", collectionName)
	val, ok := repositoryMap.Load(key)
	if ok {
		return val.(*MgoRepository)
	}
	repositoryMu.Lock()
	defer repositoryMu.Unlock()

	val, ok = repositoryMap.Load(key)
	if ok {
		return val.(*MgoRepository)
	}
	repository := &MgoRepository{
		database:   m.database,
		collection: m.database.Collection(collectionName),
		timeout:    m.timeout,
	}
	//设置索引
	indexFn(repository)
	repositoryMap.Store(key,repository)
	return repository
}

